home *** CD-ROM | disk | FTP | other *** search
/ Sound Fx / Sound Fx.iso / Software / UNZIPED / SBPLY254 / SOURCE.ZIP / _SBDMA.ASM < prev    next >
Assembly Source File  |  1996-12-05  |  29KB  |  1,373 lines

  1. _TEXT   SEGMENT WORD PUBLIC 'CODE'
  2. _TEXT   ENDS
  3.  
  4. _DATA SEGMENT WORD PUBLIC 'DATA'
  5.  
  6. _DATA   ENDS
  7.  
  8. CONST   SEGMENT WORD PUBLIC 'CONST'
  9. CONST   ENDS
  10.  
  11. _BSS    SEGMENT WORD PUBLIC 'BSS'
  12. ;GLOBAL UNINITIATED DATA GOES HERE
  13. _BSS    ENDS
  14.  
  15. DGROUP  GROUP CONST,_BSS,_DATA
  16. ;
  17.     ASSUME DS:DGROUP,SS:DGROUP
  18.  
  19. ;EXTRN EXTERNAL SUBROUTINE CALLS GO HERE
  20. ;
  21. ;
  22. ; _sbdma FAR Procedure for C Written by John A. Ball  December 5, 1996
  23. ;
  24. ; Copyright (c) 1996 John A. Ball
  25. ;
  26. ; You may copy and modify for your own use only!
  27. ; Please notify me of any errors or suggested enhancements.
  28. ;
  29. ; Plays back sound on the Sound Blaster or Sound Blaster Pro
  30. ;
  31. ;     int error sbdma(char *buffer, unsigned number_read,unsigned frequency,
  32. ;                    unsigned voc_pack);
  33. ;
  34. ;     error=sbdma(Buffer Pointer,Length,Frequency,voc_pack,Volume,channels);
  35. ;
  36. ;       Buffer Pointer is a Far pointer to the sound buffer (64k max)
  37. ;       Length is the number of sound samples to play
  38. ;       Frequency is the playback frequency in hertz
  39. ;       voc_pack is the DSP dma mode
  40. ;       Volume is the sound volume for SB Pro cards and above
  41. ;       error=0 ok
  42. ;       error 1=DMA in use
  43. ;       error 2=IRQ/DMA not Found
  44. ;       error 3=DSP not responding
  45. ;       error 4=No DSP version
  46. ;       error 5=DMA channel not correct
  47. ;       error 6=IRQ in environment not correct
  48. ;       error 7=IRQ not valid for Sound Blaster
  49. ;       error 8=Number of samples is zero
  50. ;       error -1=Sound Halted
  51. ;
  52. _TEXT   SEGMENT
  53.     ASSUME CS:_TEXT
  54.     PUBLIC _sbdma,_sb_info,_sbdelay
  55.  
  56. _sbdma PROC FAR
  57.  
  58. PARMA           EQU [BP+6]      ;Sound Buffer Pointer
  59. PARMB           EQU [BP+10]     ;Number of samples to play (Length)
  60. PARMC           EQU [BP+12]     ;Frequency to playback samples
  61. PARMD           EQU [BP+14]     ;VOC Pack mode determines DSP DMA Mode
  62. PARME           EQU [BP+16]     ;Volume for playback
  63. PARMF           EQU [BP+18]     ;Number of 8 bit channels
  64.     PUSH BP                 ;Save stack Frame
  65.     MOV BP,SP
  66.     PUSHF
  67.     PUSH DS                 ;Save registers
  68.     PUSH ES
  69.     PUSH DI
  70.  
  71.     MOV AX,DGROUP           ;Set DS = our data segment
  72.     MOV DS,AX
  73.  
  74.     JMP OVERDATA
  75. _sb_info LABEL          WORD
  76. DMAFLAG                 DW 0    ;Flag to indicate DMA for DAC in use
  77. SB_IRQ                  DW -1   ;Sound Blaster IRQ (default 5)
  78. TIME_CONST              DW 0    ;DSP Time constant
  79. SAMPLES                 DW 0    ;Number of samples to play
  80. SB_IO_ADDR              DW 0    ;Sound Blaster I/O Address
  81. SB_VER                  DW 0    ;Sound Blaster DSP Version
  82. SB_DMA                  DW 1    ;Sound Blaster DMA Channel
  83. SB_TYPE                 DW 1    ;Sound Blaster board type
  84. ERROR                   DW 0    ;Sound Blaster Hardware Error
  85. VOLUME                  DW 0    ;Sound Blaster Playback Volume
  86. STEREO                  DW 0    ;Sound Blaster mono or stereo mode
  87. PRE_MODE                DW -1   ;Previous mono stereo mode
  88. OUT_FILTER              DW 0    ;Status of output filter
  89. IN_DV                   DW 0    ;In DESQview Flag
  90. TEMP                    DW 0    ;Temporary Storage
  91. BUFFER LABEL            WORD
  92. BUFFER_ADDR             DD 0    ;Pointer to Sound Data
  93. OLD_INTERRUPT   LABEL   WORD
  94. OLD_INTERRUPT_ADDR      DD 0    ;Location of previous IRQ 5 System Interrupt
  95. SAVEPIC                 DB 0    ;Contents of PIC 1
  96. SAVEPIC2                DB 0    ;Contents of PIC 2
  97. DMA_MODE                DB 014H ;DSP DMA mode
  98. DSP_SPEED               DB 0    ;Indicates whether highspeed dma is required
  99. SB_TEST                 DB 0    ;Indicates whether SB has been tested
  100. IRQ                     DW 0    ;IRQ from environment
  101. TESTBUFFER              DB 1 DUP(080H)
  102. OLD_ISR2 LABEL          WORD
  103. OLD_ISR2_ADDR           DD 0
  104. OLD_ISR3 LABEL          WORD
  105. OLD_ISR3_ADDR           DD 0
  106. OLD_ISR5 LABEL          WORD
  107. OLD_ISR5_ADDR           DD 0
  108. OLD_ISR7 LABEL          WORD
  109. OLD_ISR7_ADDR           DD 0
  110. OLD_ISR10 LABEL         WORD
  111. OLD_ISR10_ADDR          DD 0
  112. DSP_DMA_MODE            DB 014H, 075H, 077H, 017H, 0C0H, 0C0H, 0B0H, 0B0H
  113. DMA_PAGE                DB 087H, 083H, 081H, 082H
  114.  
  115. OVERDATA:
  116.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  117.     JZ OK
  118.     MOV CS:ERROR,1          ;DMA in use error
  119.     JMP EXIT2
  120. OK:
  121.     MOV AX,0                ;Reset error
  122.     MOV CS:ERROR,AX
  123.     CMP CS:SB_IRQ,-1        ;See if IRQ was available
  124.     JNE TEST_SB
  125.     CALL SBFINDIRQ          ;Find IRQ if none given
  126.     CMP CS:ERROR,0          ;Check for errors
  127.     JE TEST_SB
  128.     JMP EXIT2
  129. TEST_SB:
  130.     CMP CS:SB_TEST,0        ;Has SB been tested?
  131.     JNE OK1
  132.     CALL FIND_DV            ;See if in Desqview?
  133.     MOV AX,CS:SB_IRQ        ;Get IRQ from environment
  134.     MOV CS:IRQ,AX           ;and save it for later
  135.     CALL SBFINDIRQ          ;Test IRQ/DMA operation
  136.     CMP CS:ERROR,0          ;Check to see if IRQ was found OK
  137.     JE IRQ_FOUND
  138.     JMP EXIT2
  139. IRQ_FOUND:
  140.     CMP CS:IRQ,0            ;See if IRQ was available
  141.     JE SBOK
  142.     MOV AX,CS:IRQ           ;if it was
  143.     CMP AX,CS:SB_IRQ        ;see if it is the same as the IRQ found
  144.     JE SBOK
  145.     MOV CS:ERROR,6          ;indicate wrong IRQ found in environment
  146. SBOK:   MOV CS:SB_TEST,1
  147.     CMP CS:ERROR,0          ;Check to see if IRQ was found ok?
  148.     JE OK1
  149.     JMP EXIT2
  150. OK1:
  151.     CMP CS:SB_TYPE,-1       ;If SB is type -1
  152.     JE OK2                  ;don't check dsp version
  153.     CMP CS:SB_VER,00
  154.     JNZ OK2
  155.     CALL GET_DSP_VER        ;Check DSP version for maximum playback
  156. OK2:    LES DI,PARMA            ;GET SOUND BUFFER POINTER
  157.     MOV CS:BUFFER,DI        ;AND SAVE
  158.     MOV DI,ES
  159.     MOV CS:BUFFER[2],DI
  160.  
  161.     MOV BX,PARMB            ;Get number of samples
  162.     CMP BX,0                ;Check for zero samples
  163.     JNE SAVE_S
  164.     MOV CS:ERROR,8
  165. SAVE_S: MOV CS:SAMPLES,BX       ;AND SAVE
  166.  
  167.     MOV AX,PARMF            ;Get number of sound channels
  168.     AND AX,02H              ;Limit to mono or stereo
  169.     MOV CS:STEREO,AX
  170.  
  171.     MOV BX,PARMC            ;Get frequency & calculate time constant
  172.     CMP CS:STEREO,2         ;Half frequency for sb16
  173.     JNE FREQOK
  174.     CMP CS:SB_VER,0400H
  175.     JL FREQOK
  176.     SHR BX,1
  177. FREQOK: MOV DX,000FH
  178.     MOV AX,04240H
  179.     DIV BX
  180.     XOR AH,AH
  181.     SUB AH,AL
  182.     MOV AL,AH
  183.     XOR AH,AH
  184.     MOV CS:TIME_CONST,AX
  185.     CMP AL,0EAH             ;Check playback speed
  186.     JBE L18
  187.     MOV AX,00EAH            ;Limit playback speed to 44,100 hz
  188.     MOV CS:TIME_CONST,AX
  189. L18:    CMP CS:SB_VER,0400H     ;Skip high speed mode for SB16
  190.     JGE L24
  191.     MOV CS:DSP_SPEED,01
  192. L24:    CMP CS:SB_VER,0200H
  193.     JAE L22
  194.     CMP CS:TIME_CONST,0D4H  ;Is playback greater than 22,727 hz?
  195.     JBE L22
  196.     MOV AX,00D4H            ;Limit to 22,727 hz if DSP version < 2.00
  197.     MOV CS:TIME_CONST,AX
  198. L22:    CMP CS:TIME_CONST,0D4H  ;Is playback less than 22,727 hz?
  199.     JA L19
  200.     MOV CS:DSP_SPEED,00
  201. L19:
  202.     MOV AX,PARMD            ;DSP DMA mode
  203.     CMP CS:SB_VER,0400H     ;Limit to 4 modes if not SB16
  204.     JGE L33
  205.     AND AX,03               ;Limit to 4 modes
  206. L33:    AND AX,07               ;Limit to 8 modes for SB16
  207.     MOV BX,AX
  208.     MOV AL,DSP_DMA_MODE[BX]
  209.     MOV CS:DMA_MODE,AL
  210.     MOV AX,PARME            ;Mixer sound volume
  211.     MOV DX,0
  212.     MOV BX,13
  213.     DIV BX
  214.     SHL AX,1
  215.     MOV CS:VOLUME,AX
  216.     CALL SET_VOLUME
  217.     CALL INSTALL_ISR        ;Install IRQ for Sound Blaster
  218.     CALL SET_MODE           ;Set mono or stereo
  219.     MOV DX,CS:SB_IO_ADDR
  220.     ADD DX,0CH
  221.     MOV AL,040H             ;Set DSP time constant
  222.     CALL sbdspw
  223.     JNC A1
  224.     MOV CS:ERROR,3          ;DSP Error
  225.     JMP EXIT
  226. A1:     MOV AX,CS:TIME_CONST
  227.     CALL sbdspw
  228.     JNC A2
  229.     MOV CS:ERROR,3          ;DSP Error
  230.     JMP EXIT
  231. A2:
  232.     INC CS:DMAFLAG          ;SET DMAFLAG TO SHOW IN USE
  233.  
  234.     MOV DX,CS:BUFFER[2]     ;Convert Buffer Address to 64k Pages & Offset
  235.     MOV AX,CS:BUFFER
  236.     CALL PNT_TO_DMA
  237.     MOV CS:BUFFER,AX        ;AND SAVE
  238.     MOV CS:BUFFER[2],DX
  239.     CALL START_DMA
  240.  
  241.     CALL IO_WAIT            ;Wait for IRQ from Sound Blaster
  242.  
  243. EXIT:
  244.     CALL RESTORE_ISR        ;Restore IRQ & PIC
  245. EXIT2:  MOV AX,CS:ERROR         ;Get error if any
  246.     POP DI                  ;Restore registers
  247.     POP ES
  248.     POP DS
  249.     POPF
  250.     POP BP                  ;RESTORE BP
  251.     RET                     ;RETURN FAR
  252.  
  253. HANDLER:                        ;Interrupt for IRQ comes here!
  254.     PUSHF
  255.     PUSH AX
  256.     PUSH BX
  257.     PUSH CX
  258.     PUSH DX
  259.     PUSH DS
  260.     PUSH ES
  261.     sti                     ;enable interrupts or computer will crash
  262.     CALL sbdsprt
  263.     CMP CS:SB_IRQ,10
  264.     JE ACKIRQ10
  265.     MOV AL,020H
  266.     OUT 020H,AL
  267.     JMP DONE_ACK
  268. ACKIRQ10:
  269.     MOV AL,020H
  270.     OUT 020H,AL
  271.     OUT 0A0H,AL
  272. DONE_ACK:
  273.     CMP CS:SAMPLES,0        ;Anymore samples?
  274.     JE L13
  275.     INC CS:BUFFER[2]        ;Increment to next page
  276.     MOV CS:BUFFER,0000      ;and set offset to zero
  277.     CALL START_DMA
  278.     JMP EXIT1
  279. L13:    DEC CS:DMAFLAG          ;Indicate it is
  280.  
  281. EXIT1:  POP ES
  282.     POP DS
  283.     POP DX
  284.     POP CX
  285.     POP BX
  286.     POP AX
  287.     POPF
  288.     IRET
  289.  
  290. _sbdma  ENDP
  291.  
  292. sbdspwt PROC NEAR
  293.  
  294. ;Write to DSP with timeout
  295.  
  296.     PUSH CX
  297.     MOV CX,200H
  298.     MOV AH,AL
  299. L1:     IN AL,DX
  300.     JMP $+2
  301.     OR AL,AL
  302.     JNS L2
  303.     LOOP L1
  304.     STC
  305.     JMP L3
  306. L2:     MOV AL,AH
  307.     OUT DX,AL
  308.     CLC
  309. L3:     POP CX
  310.     RET
  311.  
  312. sbdspwt  ENDP
  313.  
  314.  
  315. sbdspr PROC NEAR
  316.  
  317. ;Read DSP
  318.  
  319.     PUSH DX
  320.     MOV DX,CS:SB_IO_ADDR
  321.     ADD DL,0EH
  322.     SUB AL,AL
  323. L7:     IN AL,DX
  324.     JMP $+2
  325.     OR AL,AL
  326.     JNS L7
  327.     SUB DL,04H
  328.     IN AL,DX
  329.     POP DX
  330.     RET
  331.  
  332. sbdspr ENDP
  333.  
  334. sbdsprt PROC NEAR
  335.  
  336. ;Read DSP with timeout
  337.  
  338.     PUSH CX
  339.     PUSH DX
  340.     MOV DX,CS:SB_IO_ADDR
  341.     ADD DL,0EH
  342.     MOV CX,0200H
  343. L4:     IN AL,DX
  344.     JMP $+2
  345.     OR AL,AL
  346.     JS L5
  347.     LOOP L4
  348.     STC
  349.     JMP L6
  350. L5:     SUB DL,04H
  351.     IN AL,DX
  352.     CLC
  353. L6:     POP DX
  354.     POP CX
  355.     RET
  356.  
  357. sbdsprt ENDP
  358.  
  359. ;Write to DSP
  360.  
  361. sbdspw PROC NEAR
  362.  
  363.     PUSH CX
  364.     PUSH BX
  365.     MOV AH,AL
  366.     MOV BX,10
  367.     MOV CX,0ffffH           ;After timeout send value anyway
  368.     CLC
  369. L8:     IN AL,DX
  370.     JMP $+2
  371.     JMP $+2
  372.     OR AL,AL
  373.     JNS L8E
  374.     LOOP L8
  375.     DEC BX
  376.     OR BX,BX
  377.     JNZ L8
  378.     STC                     ;Set Carry to indicate timeout
  379. L8E:    MOV AL,AH
  380.     OUT DX,AL
  381.     POP BX
  382.     POP CX
  383.     RET
  384.  
  385. sbdspw ENDP
  386.  
  387. ;Convert FAR pointer to 64k pages and offset
  388.  
  389. PNT_TO_DMA PROC NEAR
  390.  
  391.     PUSH CX
  392.     MOV CL,4
  393.     ROL DX,CL
  394.     MOV CX,DX
  395.     AND DX,0FH
  396.     AND CX,0FFF0H
  397.     ADD AX,CX
  398.     ADC DX,0
  399.     POP CX
  400.     RET
  401.  
  402. PNT_TO_DMA ENDP
  403.  
  404. INSTALL_ISR PROC NEAR
  405.  
  406.     pushf
  407.     push ds
  408.     push es
  409.     CLI
  410.     MOV AX,CS:SB_IRQ
  411.     CMP AX,02
  412.     JE INSTALL
  413.     CMP AX,03
  414.     JE INSTALL
  415.     CMP AX,05
  416.     JE INSTALL
  417.     CMP AX,07
  418.     JE INSTALL
  419.     CMP AX,10
  420.     JE INSTALL
  421.     MOV CS:ERROR,7
  422.     MOV AX,5                ;Use default if error
  423. INSTALL:
  424.     CALL IRQ_VECT
  425.     MOV AH,035H             ;GET INTERRUPT for IRQ 5 AND SAVE IT
  426.     INT 21H
  427.     CLI
  428.     MOV CS:OLD_INTERRUPT,BX
  429.     MOV CS:OLD_INTERRUPT[2],ES
  430.     MOV AX,CS
  431.     MOV DS,AX
  432.     MOV AX,CS:SB_IRQ
  433.     CALL IRQ_VECT
  434.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 5
  435.     LEA DX,HANDLER
  436.     INT 21H
  437.     pop es
  438.     pop ds
  439.     popf
  440.  
  441.     MOV AX,CS:SB_IRQ        ;IRQ 5
  442.     AND AL,08H
  443.     JZ L11
  444.     IN AL,021H              ;ENABLE IRQ from PIC
  445.     MOV CS:SAVEPIC,AL
  446.     AND AL,0FBH
  447.     OUT 021H,AL
  448.     MOV DX,00A1H
  449.     JMP L12
  450. L11:    MOV DX,021H
  451. L12:    MOV CX,CS:SB_IRQ        ;Sound Blaster IRQ
  452.     AND CL,07H
  453.     MOV AH,01
  454.     SHL AH,CL
  455.     NOT AH
  456.     IN AL,DX
  457.     MOV CS:SAVEPIC2,AL
  458.     AND AL,AH
  459.     OUT DX,AL
  460.     RET
  461.  
  462. INSTALL_ISR ENDP
  463.  
  464. RESTORE_ISR PROC NEAR
  465. ;
  466. ;Restore IRQ and PICs before exiting
  467. ;
  468.     PUSH AX
  469.     MOV AX,0
  470.     MOV CS:DMAFLAG,AX       ;Indicate DMA done
  471.     LDS DX,CS:OLD_INTERRUPT_ADDR
  472.     MOV AX,CS:SB_IRQ
  473.     CALL IRQ_VECT
  474.     CLI
  475.     MOV AH,025H             ;Restore old IRQ 5
  476.     INT 21h
  477.     CLI
  478.     MOV AX,CS:SB_IRQ        ;Restore PICs
  479.     AND AL,08
  480.     JZ L31
  481.     MOV AL,CS:SAVEPIC
  482.     OUT 021H,AL
  483.     MOV DX,00A1H
  484.     JMP L32
  485. L31:    MOV DX,0021H
  486. L32:    MOV AL,CS:SAVEPIC2
  487.     OUT DX,AL
  488.     POP AX
  489.     RET
  490.  
  491. RESTORE_ISR ENDP
  492.  
  493. IO_WAIT PROC NEAR
  494. ;
  495. ; Gives up time slice if time and stops dma if ESC key hit
  496. ;
  497. IOWAIT1:
  498.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  499.     JE DMA_DONE             ;Wait until done
  500.     MOV AH,01H              ;See if key pressed
  501.     INT 16H
  502.     JZ GET_DMA
  503. KEY_PRESS:
  504.     MOV AX,0
  505.     INT 16H                 ;Get the pressed key
  506.     CMP AL,1BH              ;See if ESC key hit?
  507.     JNE GET_DMA
  508.     CALL HALT_DMA
  509.     CMP CS:ERROR,0          ;Check for error when halting DMA
  510.     JNE EXIT_IO
  511.     MOV CS:ERROR,0FFFFH     ;EXIT ERROR CODE
  512.     JMP EXIT_IO
  513. ;        MOV CS:DMAFLAG,0        ;Reset DMAFLAG to show done
  514. ;        MOV AX,-1               ;and indicate sound halted
  515.     JMP EXIT_IO
  516. GET_DMA:
  517.     MOV AX,CS:SB_DMA        ;Determine DMA count register
  518.     SHL AX,1
  519.     ADD AX,1
  520.     MOV DX,AX
  521.     IN AL,DX                ;Get DMA countdown
  522.     MOV AH,AL
  523.     IN AL,DX
  524.     XCHG AL,AH
  525.     CMP AX,5000             ;If greater than 5000 bytes to go
  526.     JG GIVE_CPU             ;then give up some cpu time
  527. WAIT_HERE:
  528.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  529.     JE DMA_DONE             ;Wait until done
  530.     JMP WAIT_HERE
  531. GIVE_CPU:
  532.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  533.     JE DMA_DONE             ;Wait until done
  534.     CALL GIVE_SLICE         ;Give some time up
  535.     JMP IOWAIT1
  536. DMA_DONE:
  537.     MOV AX,0                ;OK
  538. EXIT_IO:
  539.     RET
  540.  
  541.  
  542. IO_WAIT ENDP
  543.  
  544.  
  545. ; Start DMA transfer
  546.  
  547. START_DMA PROC NEAR
  548.  
  549.     MOV AX,CS:SB_DMA
  550.     AND AX,03H              ;Limit DMA channels to (0-3) 8-BIT
  551.     MOV CS:SB_DMA,AX
  552.     MOV AX,CS:SB_DMA
  553.     ADD AL,04
  554.     OUT 0AH,AL              ;Set mask bit channel 1
  555.     JMP $+2
  556.     MOV AL,0FFH
  557.     OUT 0CH,AL              ;Clear byte pointer flip/flop
  558.     JMP $+2
  559.     MOV AL,048H             ;Write mode
  560.     ADD AX,CS:SB_DMA        ;plus DMA channel
  561.     OUT 0BH,AL              ;Single mode select read channel 1
  562.     JMP $+2
  563.     MOV BX,CS:SB_DMA        ;Get DMA Page Register
  564.     MOV DX,0
  565.     MOV DL,CS:DMA_PAGE[BX]
  566.     MOV AX,CS:BUFFER[2]
  567.     OUT DX,AL               ;Set DMA page register
  568.     JMP $+2
  569.     MOV BX,CS:BUFFER
  570.     MOV DX,CS:SB_DMA        ;Determine memory address register
  571.     SHL DX,1
  572.     MOV AL,BL
  573.     OUT DX,AL               ;Set base and current address
  574.     JMP $+2
  575.     MOV AL,BH
  576.     OUT DX,AL
  577.     JMP $+2
  578.     XOR BX,-1               ;(65536-bx) = #bytes that can be transfered
  579.     MOV AX,CS:SAMPLES       ;Get # of samples & subtract 1
  580.     DEC AX                  ; # SAMPLES - 1
  581.     CMP AX,BX               ;# SAMPLES > # that can be DMA?
  582.     JBE L10
  583.     MOV AX,BX               ;If yes, use # that can be DMA
  584. L10:
  585.     CLI
  586.     PUSH AX
  587.     INC DX
  588.     OUT DX,AL               ;Base & current word count
  589.     JMP $+2
  590.     MOV AL,AH
  591.     OUT DX,AL
  592.     JMP $+2
  593.     POP AX
  594.     STI
  595.     PUSH AX                 ;Save number of samples to play
  596.     INC AX                  ;restore count
  597.     SUB CS:SAMPLES,AX       ;Subtract # that can be DMA
  598.     MOV AX,CS:SB_DMA
  599.     OUT 0AH,AL              ;Clear channel 1 mask bit to start DMA
  600.  
  601.     MOV DX,CS:SB_IO_ADDR
  602.     ADD DX,0CH
  603.     CMP CS:DSP_SPEED,01     ;Check for high speed mode
  604.     JNZ L21
  605.     MOV AL,048H
  606.     CALL sbdspw
  607.     JNC A11
  608.     MOV CS:ERROR,3          ;DSP not responding
  609.     JMP L20
  610. A11:
  611.     POP AX                  ;Get number of samples & send to DSP
  612.     MOV BX,AX
  613.     CALL sbdspw
  614.     JNC A12
  615.     MOV CS:ERROR,3          ;DSP not responding
  616.     JMP L20
  617. A12:
  618.     MOV AL,BH
  619.     CALL sbdspw
  620.     JNC A13
  621.     MOV CS:ERROR,3          ;DSP not responding
  622.     JMP L20
  623. A13:
  624.     MOV AL,091H             ;High Speed DMA mode
  625.     CALL SBDSPW
  626.     JNC A14
  627.     MOV CS:ERROR,3          ;DSP not responding
  628.     JMP L20
  629. A14:
  630.     JMP L20
  631. L21:
  632.     MOV AL,CS:DMA_MODE      ;DSP DMA mode for 8-bit DAC
  633.     CALL sbdspw
  634.     JNC A15
  635.     MOV CS:ERROR,3          ;DSP not responding
  636.     JMP L20
  637. A15:
  638.     CMP CS:DMA_MODE,0C0H    ;SB16 stereo?
  639.     JNE A15A
  640.     MOV AX,020H
  641.     CALL sbdspw
  642.     JNC A15A
  643.     MOV CS:ERROR,3          ;DSP not responding
  644.     JMP L20
  645. A15A:   POP AX                  ;Get number of samples & send to DSP
  646.     MOV BX,AX
  647.     CALL sbdspw
  648.     JNC A16
  649.     MOV CS:ERROR,3          ;DSP not responding
  650.     JMP L20
  651. A16:
  652.     MOV AL,BH
  653.     CALL sbdspw
  654.     JNC L20
  655.     MOV CS:ERROR,3          ;DSP not responding
  656. L20:    RET
  657. START_DMA ENDP
  658.  
  659. ; Calculate interrupt vector for Sound Blaster IRQ (5)
  660.  
  661. IRQ_VECT PROC NEAR
  662.  
  663.     PUSH BX
  664.     MOV BL,AL
  665.     AND BL,08
  666.     JZ L14
  667.     AND AL,07
  668.     ADD AL,070H
  669.     JMP L15
  670. L14:    ADD AL,08
  671. L15:    CBW
  672.     POP BX
  673.     RET
  674.  
  675. IRQ_VECT ENDP
  676.  
  677. SBFINDIRQ PROC NEAR
  678.  
  679. ; Install ISRs for possible Sound Blaster IRQs
  680.  
  681.     PUSHF
  682.     PUSH DX
  683.     PUSH CX
  684.  
  685.     MOV AX,CS
  686.     MOV DS,AX
  687.     MOV ES,AX
  688.  
  689.     MOV AL,02               ;IRQ 2
  690.     CALL IRQ_VECT           ;Get IRQ ISR address
  691.     PUSH AX
  692.     MOV AH,035H             ;Get old ISR address and save
  693.     INT 21H
  694.     MOV CS:OLD_ISR2,BX
  695.     MOV CS:OLD_ISR2[2],ES
  696.  
  697.     MOV AX,CS
  698.     MOV DS,AX
  699.     MOV ES,AX
  700.     POP AX
  701.     CLI
  702.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 2
  703.     LEA DX,HANDLER2
  704.     INT 21H
  705.  
  706.     MOV AL,03               ;IRQ 3
  707.     CALL IRQ_VECT
  708.     PUSH AX
  709.     MOV AH,035H             ;Get old ISR address and save
  710.     INT 21H
  711.     MOV CS:OLD_ISR3,BX
  712.     MOV CS:OLD_ISR3[2],ES
  713.  
  714.     MOV AX,CS
  715.     MOV DS,AX
  716.     MOV ES,AX
  717.     POP AX
  718.     CLI
  719.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 3
  720.     LEA DX,HANDLER3
  721.     INT 21H
  722.  
  723.     MOV AL,05               ;IRQ 5
  724.     CALL IRQ_VECT
  725.     PUSH AX
  726.     MOV AH,035H             ;Get old ISR address and save
  727.     INT 21H
  728.     MOV CS:OLD_ISR5,BX
  729.     MOV CS:OLD_ISR5[2],ES
  730.  
  731.     MOV AX,CS
  732.     MOV DS,AX
  733.     MOV ES,AX
  734.     POP AX
  735.     CLI
  736.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 5
  737.     LEA DX,HANDLER5
  738.     INT 21H
  739.  
  740.     MOV AL,07               ;IRQ 7
  741.     CALL IRQ_VECT
  742.     PUSH AX
  743.     MOV AH,035H             ;Get old ISR address and save
  744.     INT 21H
  745.     MOV CS:OLD_ISR7,BX
  746.     MOV CS:OLD_ISR7[2],ES
  747.  
  748.     MOV AX,CS
  749.     MOV DS,AX
  750.     MOV ES,AX
  751.     POP AX
  752.     CLI
  753.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 7
  754.     LEA DX,HANDLER7
  755.     INT 21H
  756.  
  757.     MOV AL,10               ;IRQ 10
  758.     CALL IRQ_VECT
  759.     PUSH AX
  760.     MOV AH,035H             ;Get old ISR address and save
  761.     INT 21H
  762.     MOV CS:OLD_ISR10,BX
  763.     MOV CS:OLD_ISR10[2],ES
  764.  
  765.     MOV AX,CS
  766.     MOV DS,AX
  767.     MOV ES,AX
  768.     POP AX
  769.     CLI
  770.     MOV AH,025H             ;AND SET NEW INTERRUPT IRQ 10
  771.     LEA DX,HANDLER10
  772.     INT 21H
  773.     IN AL,021H              ;ENABLE IRQS from PIC1
  774.     MOV CS:SAVEPIC,AL
  775.     AND AL,053H
  776.     OUT 021H,AL
  777.     IN AL,0A1H              ;ENABLE IRQS from PIC2
  778.     MOV CS:SAVEPIC2,AL
  779.     AND AL,0FBH
  780.     OUT 0A1H,AL
  781.  
  782.     MOV CS:SB_IRQ,0         ;Set IRQ to 0 and see if it changes
  783.  
  784.     CALL TEST_DMA           ;Start short DMA and see if it works
  785.     CMP CS:ERROR,0
  786.     JNE FOUNDIRQ
  787.  
  788.     MOV CX,0ffffh
  789. IRQWAIT:
  790.     CALL GIVE_SLICE         ;Give some time up
  791.     MOV AX,CS:SB_IRQ        ;Wait for interrupt to occur
  792.     CMP AX,02               ;with Time-Out
  793.     JE FOUNDIRQ
  794.     CMP AX,03
  795.     JE FOUNDIRQ
  796.     CMP AX,05
  797.     JE FOUNDIRQ
  798.     CMP AX,07
  799.     JE FOUNDIRQ
  800.     CMP AX,10
  801.     JE FOUNDIRQ
  802.     LOOP IRQWAIT
  803.  
  804.     IN AL,08H               ;Read DMA status register
  805.     JMP $+2
  806.     IN AL,08H               ;and again
  807.     CMP AL,0                ;Is status all clear?
  808.     JE IRQERR               ;If 0 then IRQ error
  809.     MOV CS:ERROR,5          ;DMA error
  810.     MOV DX,CS:SB_IO_ADDR
  811.     ADD DX,0CH
  812.     MOV AL,080H
  813.     OUT DX,AL               ;Send 1 byte to fix DSP
  814.     MOV CX,0ffffh           ;Wait for interrupt
  815. IRQWAIT1:
  816.     CALL GIVE_SLICE         ;Give some time up
  817.     MOV AX,CS:SB_IRQ        ;Wait for interrupt to occur
  818.     CMP AX,02               ;with Time-Out
  819.     JE FOUNDIRQ
  820.     CMP AX,03
  821.     JE FOUNDIRQ
  822.     CMP AX,05
  823.     JE FOUNDIRQ
  824.     CMP AX,07
  825.     JE FOUNDIRQ
  826.     CMP AX,10
  827.     JE FOUNDIRQ
  828.     LOOP IRQWAIT1
  829.  
  830. IRQERR: MOV CS:ERROR,2          ;IRQ error (IRQ did not occur)
  831.  
  832. FOUNDIRQ:
  833.     CLI
  834.     MOV AL,CS:SAVEPIC       ;Restore IRQs as found
  835.     OUT 021H,AL
  836.     MOV AL,CS:SAVEPIC2
  837.     OUT 0A1H,AL
  838.  
  839.     MOV AL,02               ;IRQ 2
  840.     CALL IRQ_VECT
  841.     CLI
  842.     MOV AH,025H
  843.     LDS DX,CS:OLD_ISR2_ADDR
  844.     INT 21H                 ;Restore OLD vector
  845.  
  846.     MOV AL,03               ;IRQ 3
  847.     CALL IRQ_VECT
  848.     CLI
  849.     MOV AH,025H
  850.     LDS DX,CS:OLD_ISR3_ADDR
  851.     INT 21H                 ;Restore OLD vector
  852.  
  853.     MOV AL,05               ;IRQ 5
  854.     CALL IRQ_VECT
  855.     CLI
  856.     MOV AH,025H
  857.     LDS DX,CS:OLD_ISR5_ADDR
  858.     INT 21H                 ;Restore OLD vector
  859.  
  860.     MOV AL,07               ;IRQ 7
  861.     CALL IRQ_VECT
  862.     CLI
  863.     MOV AH,025H
  864.     LDS DX,CS:OLD_ISR7_ADDR
  865.     INT 21H                 ;Restore OLD vector
  866.  
  867.     MOV AL,10               ;IRQ 10
  868.     CALL IRQ_VECT
  869.     CLI
  870.     MOV AH,025H
  871.     LDS DX,CS:OLD_ISR10_ADDR
  872.     INT 21H                 ;Restore OLD vector
  873.  
  874.     MOV AX,CS:SB_IRQ        ;return with SB irq
  875.  
  876.     POP CX
  877.     POP DX
  878.     POPF
  879.     RET
  880.  
  881. HANDLER2:
  882.     PUSH DX
  883.     PUSH AX
  884.     MOV DX,CS:SB_IO_ADDR
  885.     ADD DX,0EH
  886.     IN AL,DX
  887.     MOV CS:SB_IRQ,02
  888.     MOV AL,020H
  889.     OUT 20H,AL
  890.     POP AX
  891.     POP DX
  892.     IRET
  893.  
  894. HANDLER3:
  895.     PUSH DX
  896.     PUSH AX
  897.     MOV DX,CS:SB_IO_ADDR
  898.     ADD DX,0EH
  899.     IN AL,DX
  900.     MOV CS:SB_IRQ,03
  901.     MOV AL,020H
  902.     OUT 20H,AL
  903.     POP AX
  904.     POP DX
  905.     IRET
  906.  
  907. HANDLER5:
  908.     PUSH DX
  909.     PUSH AX
  910.     MOV DX,CS:SB_IO_ADDR
  911.     ADD DX,0EH
  912.     IN AL,DX
  913.     MOV CS:SB_IRQ,05
  914.     MOV AL,020H
  915.     OUT 20H,AL
  916.     POP AX
  917.     POP DX
  918.     IRET
  919.  
  920. HANDLER7:
  921.     PUSH DX
  922.     PUSH AX
  923.     MOV DX,CS:SB_IO_ADDR
  924.     ADD DX,0EH
  925.     IN AL,DX
  926.     MOV CS:SB_IRQ,07
  927.     MOV AL,020H
  928.     OUT 20H,AL
  929.     POP AX
  930.     POP DX
  931.     IRET
  932.  
  933. HANDLER10:
  934.     PUSH DX
  935.     PUSH AX
  936.     MOV DX,CS:SB_IO_ADDR
  937.     ADD DX,0EH
  938.     IN AL,DX
  939.     MOV CS:SB_IRQ,10
  940.     MOV AL,020H
  941.     OUT 020H,AL
  942.     OUT 0A0H,AL
  943.     POP AX
  944.     POP DX
  945.     IRET
  946.  
  947. SBFINDIRQ ENDP
  948.  
  949. ;Get the Sound Blaster DSP version
  950.  
  951. GET_DSP_VER PROC NEAR
  952.  
  953.     PUSH CX
  954.     MOV CX,10
  955.     MOV DX,CS:SB_IO_ADDR
  956.     ADD DX,0CH
  957.     MOV AL,0E1H
  958.     CALL sbdspw
  959.     JNC A21
  960.     MOV CS:ERROR,3          ;DSP not responding
  961.     JMP L23
  962. A21:
  963. G1:     CALL sbdsprt
  964.     CMP AL,0AAH             ;Fix error in reading version
  965.     JNZ G2
  966.     LOOP G1
  967.     MOV CS:ERROR,4          ;DSP error not responding or no version
  968.     JMP L23
  969. G2:     MOV AH,AL
  970.     CALL sbdsprt
  971.     MOV CS:SB_VER,AX
  972.     MOV DX,CS:SB_IO_ADDR
  973.     ADD DX,0CH
  974.     MOV AL,0E1H
  975.     CALL sbdspw
  976.     JNC A22
  977.     MOV CS:ERROR,3          ;DSP not responding
  978.     JMP L23
  979. A22:
  980.     CALL sbdsprt
  981.     MOV AH,AL
  982.     CALL sbdsprt
  983.     CMP CS:SB_VER,AX
  984.     JE L23
  985.     MOV AX,00
  986.     MOV CS:SB_VER,AX
  987. L23:    
  988.     POP CX
  989.     RET
  990.  
  991. GET_DSP_VER ENDP
  992.  
  993. ; Test Sound Blaster DMA transfer
  994.  
  995. TEST_DMA PROC NEAR
  996.  
  997.     MOV DX,CS
  998.     LEA AX,TESTBUFFER
  999.     CALL PNT_TO_DMA
  1000.     PUSH AX
  1001.     PUSH DX                 ;SAVE CONVERTED BUFFER ADDRESS
  1002.     MOV AL,0FFH
  1003.     OUT 00CH,AL             ;Clear byte pointer flip/flop
  1004.     JMP $+2
  1005.     MOV AX,CS:SB_DMA
  1006.     ADD AL,04
  1007.     OUT 0AH,AL              ;Set mask bit to channel
  1008.     JMP $+2
  1009.     MOV AL,048H
  1010.     ADD AX,CS:SB_DMA
  1011.     OUT 0BH,AL              ;Single mode select read channel
  1012.     JMP $+2
  1013.     MOV BX,CS:SB_DMA
  1014.     MOV DX,0
  1015.     MOV DL,CS:DMA_PAGE[BX]
  1016.     POP BX                  ;Restore converted buffer address
  1017.     MOV AL,BL
  1018.     OUT DX,AL               ;Set DMA page register
  1019.     JMP $+2
  1020.     POP AX
  1021.     MOV DX,CS:SB_DMA        ;Determine memory address register
  1022.     SHL DX,1
  1023.     OUT DX,AL               ;Set base and current address
  1024.     JMP $+2
  1025.     MOV AL,AH
  1026.     OUT DX,AL
  1027.     JMP $+2
  1028.     MOV BX,AX
  1029.     XOR BX,-1               ;(65536-BX) = # BYTES THAT CAN BE TRANSFERED
  1030.     MOV AX,0                ;# samples - 1
  1031.     CMP AX,BX
  1032.     JBE L100
  1033.     MOV AX,BX
  1034. L100:
  1035.     CLI
  1036.     INC DX
  1037.     OUT DX,AL             ;Base & current word count
  1038.     JMP $+2
  1039.     MOV AL,AH
  1040.     OUT DX,AL
  1041.     JMP $+2
  1042.     STI
  1043.     MOV AX,CS:SB_DMA
  1044.     OUT 0AH,AL            ;Clear channel 1 mask bit to start DMA
  1045.     JMP $+2
  1046.     MOV DX,CS:SB_IO_ADDR
  1047.     ADD DX,0CH
  1048.     MOV AL,040H
  1049.     CALL sbdspw            ;Set DSP time constant
  1050.     JNC A31
  1051.     MOV CS:ERROR,3         ;DSP not responding
  1052.     JMP A35
  1053. A31:
  1054.     MOV AL,064H
  1055.     CALL sbdspw
  1056.     JNC A32
  1057.     MOV CS:ERROR,3         ;DSP not responding
  1058.     JMP A35
  1059. A32:
  1060.     MOV AL,014H
  1061.     CALL sbdspw            ;DMA mode 8-bit DAC
  1062.     JNC A33
  1063.     MOV CS:ERROR,3         ;DSP not responding
  1064.     JMP A35
  1065. A33:
  1066.     MOV AX,0000            ;Number of bytes to be sent to DSP is 1
  1067.     CALL sbdspw            ;#samples to be sent to DSP
  1068.     JNC A34
  1069.     MOV CS:ERROR,3         ;DSP not responding
  1070.     JMP A35
  1071. A34:
  1072.     MOV AL,AH
  1073.     CALL sbdspw
  1074.     JNC A35
  1075.     MOV CS:ERROR,3         ;DSP not responding
  1076. A35:
  1077.     RET
  1078.  
  1079. TEST_DMA ENDP
  1080.  
  1081. ; Halt DMA transfer
  1082.  
  1083. HALT_DMA PROC NEAR
  1084.  
  1085.     MOV AX,CS               ;Set DS to CS
  1086.     MOV DS,AX
  1087.     MOV AX,0001
  1088.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  1089.     JE H_END                ;Wait until done
  1090.     CMP CS:DSP_SPEED,01     ;In high speed?
  1091.     JNZ H_RESET
  1092.     CALL DSP_RESET          ;In high speed DSP must be reset first
  1093. H_RESET:
  1094.     CALL STOP_DMA
  1095.     CALL RESTORE            ;Restore IRQ, etc.
  1096. H_END:  RET
  1097.  
  1098. HALT_DMA ENDP
  1099.  
  1100. DSP_RESET PROC NEAR
  1101.  
  1102.     MOV DX,CS:SB_IO_ADDR
  1103.     ADD DL,06
  1104.     MOV AL,01
  1105.     OUT DX,AL
  1106.     IN AL,DX
  1107.     IN AL,DX
  1108.     IN AL,DX
  1109.     IN AL,DX
  1110.     SUB AL,AL
  1111.     OUT DX,AL
  1112.     MOV BL,10H
  1113. D_GET:  CALL sbdsprt
  1114.     CMP AL,0AAH
  1115.     JZ D_END
  1116.     DEC BL
  1117.     JNZ D_GET
  1118.     MOV AX,0002             ;I/O read/write fail
  1119.     STC
  1120.     JMP D_END1
  1121. D_END:  SUB AX,AX
  1122. D_END1: OR AX,AX
  1123.     RET
  1124.  
  1125. DSP_RESET ENDP
  1126.  
  1127. STOP_DMA PROC NEAR
  1128.  
  1129.     PUSHF
  1130.     PUSH SI
  1131.     MOV AH,0D0H             ;HALT DMA IN PROGRESS
  1132.     MOV BX, OFFSET DMAFLAG
  1133.     SUB CX,CX
  1134.     MOV DX,CS:SB_IO_ADDR
  1135.     ADD DL,0CH
  1136.     MOV SI,0FFFFH
  1137. S1:     STI
  1138.     CMP CL,[BX]             ;Is dsp in use?
  1139.     JZ SE
  1140.     CLI
  1141.     IN AL,DX
  1142.     OR AL,AL
  1143.     JS S2
  1144.     DEC SI
  1145.     JNZ S1
  1146. S5:     MOV CS:ERROR,3          ;DSP error (not responding)
  1147.     JMP SE
  1148. S2:     MOV SI,0FFFFH           ;Timeout Period
  1149. S3:     DEC SI
  1150.     JZ S5
  1151.     IN AL,DX
  1152.     OR AL,AL
  1153.     JS S3
  1154.     MOV AL,AH
  1155.     OUT DX,AL
  1156. SE:     POP SI
  1157.     POPF
  1158.     RET
  1159.  
  1160. STOP_DMA ENDP
  1161.  
  1162. RESTORE PROC NEAR
  1163.  
  1164.     MOV AL,04               ;DMA channel mask register
  1165.     ADD AX,CS:SB_DMA
  1166.     OUT 0AH,AL
  1167.     MOV AX,0
  1168.     MOV CS:DMAFLAG,AX       ;Indicate it is
  1169.     LDS DX,CS:OLD_INTERRUPT_ADDR
  1170.     MOV AX,CS:SB_IRQ
  1171.     CALL IRQ_VECT
  1172.     CLI
  1173.     MOV AH,025H             ;Restore old IRQ 5
  1174.     INT 21h
  1175.     CLI
  1176.     MOV AX,CS:SB_IRQ        ;Restore PICs
  1177.     AND AL,08
  1178.     JZ R10
  1179.     MOV AL,CS:SAVEPIC
  1180.     OUT 021H,AL
  1181.     MOV DX,00A1H
  1182.     JMP R11
  1183. R10:    MOV DX,0021H
  1184. R11:    MOV AL,CS:SAVEPIC2
  1185.     OUT DX,AL
  1186.     MOV DX,CS:SB_IO_ADDR    ;Acknowledge DSP interrupt
  1187.     ADD DL,0EH
  1188.     IN AL,DX
  1189.     RET
  1190.  
  1191. RESTORE ENDP
  1192.  
  1193. _sbdelay PROC FAR
  1194. ;
  1195. ; _sbdelay FAR Procedure for C Written by John A. Ball   January 9, 1994
  1196. ;
  1197. ; Causes a time delay using the Sound Blaster DSP
  1198. ;
  1199. ;       int error sbdelay(char tc, int period);
  1200. ;
  1201. PARMA1          EQU [BP+6]      ;Time Constant
  1202. PARMB1          EQU [BP+8]      ;Delay period
  1203.  
  1204.     PUSH BP                 ;Save stack Frame
  1205.     MOV BP,SP
  1206.     PUSHF
  1207.     PUSH DS                 ;Save registers
  1208.     PUSH ES
  1209.     PUSH DI
  1210.  
  1211.     MOV AX,DGROUP           ;Set DS = our data segment
  1212.     MOV DS,AX
  1213.  
  1214.     CMP CS:DMAFLAG,0        ;Is DMAFLAG for DAC still in Use?
  1215.     JZ DELAY
  1216.     MOV CS:ERROR,1          ;DMA in use error
  1217.     JMP EXIT3
  1218. DELAY:  CMP CS:SB_IRQ,2         ;See if there is a known valid IRQ
  1219.     JE DELAY1
  1220.     CMP CS:SB_IRQ,3
  1221.     JE DELAY1
  1222.     CMP CS:SB_IRQ,5
  1223.     JE DELAY1
  1224.     CMP CS:SB_IRQ,7
  1225.     JE DELAY1
  1226.     CMP CS:SB_IRQ,10
  1227.     JE DELAY1
  1228.     CALL SBFINDIRQ          ;Else find the IRQ
  1229.     MOV CS:SB_TEST,1
  1230.     CMP CS:ERROR,0          ;Check to see if IRQ was found
  1231.     JE DELAY1
  1232.     JMP EXIT3
  1233. DELAY1:
  1234.     CALL INSTALL_ISR        ;Install ISR for Sound Blaster IRQ & PIC
  1235.  
  1236.     MOV CX,PARMA1           ;GET TIME CONSTANT
  1237.     MOV BX,PARMB1           ;Get delay period
  1238.     MOV DX,CS:SB_IO_ADDR
  1239.     ADD DX,0CH
  1240.     MOV AL,040H             ;Set Time Constant
  1241.     CALL sbdspw
  1242.     MOV AL,CL
  1243.     CALL sbdspw
  1244.     MOV AL,080H             ;Set Silence Length
  1245.     CALL sbdspw
  1246.     MOV AL,BL               ;and send Period
  1247.     CALL sbdspw
  1248.     MOV AL,BH
  1249.     CALL sbdspw
  1250.  
  1251.     INC CS:DMAFLAG          ;SET DMAFLAG TO SHOW IN USE
  1252.  
  1253.     CALL IO_WAIT            ; and wait for IRQ to occur
  1254.  
  1255.     CALL RESTORE_ISR        ; RESTORE ISR and PIC
  1256. EXIT3:  MOV AX,CS:ERROR
  1257.     POP DI                  ;Restore registers
  1258.     POP ES
  1259.     POP DS
  1260.     POPF
  1261.     POP BP                  ;RESTORE BP
  1262.     RET
  1263. _sbdelay ENDP
  1264.  
  1265. GIVE_SLICE PROC NEAR
  1266.     CMP CS:IN_DV,0          ;See if in DESQview?
  1267.     JNE DV
  1268.     INT 28H                 ;MS-DOS idle handler
  1269.     MOV AX,1680H
  1270.     INT 2FH                 ;MS-DOS idle call
  1271.     JMP DV_EXIT
  1272. DV:
  1273.     MOV AX,1000H            ;Give up time slice to DESQview
  1274.     INT 15H
  1275. DV_EXIT:
  1276.     RET
  1277. GIVE_SLICE ENDP
  1278.  
  1279. FIND_DV PROC NEAR
  1280.     PUSH BX
  1281.     PUSH CX
  1282.     PUSH DX
  1283.     MOV CX,'DE'
  1284.     MOV DX,'SQ'
  1285.     MOV AX,2B01H
  1286.     INT 21H
  1287.     CMP AL,0FFH
  1288.     JE NO_DV
  1289.     MOV AX,BX
  1290.     MOV CS:IN_DV,1
  1291.     JMP E_F
  1292. NO_DV:
  1293.     MOV AX,0
  1294. E_F:
  1295.     POP DX
  1296.     POP CX
  1297.     POP BX
  1298.     RET
  1299. FIND_DV ENDP
  1300.  
  1301. SET_VOLUME PROC NEAR
  1302.  
  1303.     MOV AX,CS:SB_VER        ;Get DSP version and see if card has mixer
  1304.     CMP AX,0300H            ;Versions 3 and above have mixer chip
  1305.     JL EXIT_VOL
  1306.     MOV AX,CS:VOLUME        ;Get volume and convert to mixer format
  1307.     MOV CX,4
  1308.     MOV BX,AX
  1309.     SHL AX,CL
  1310.     ADD BX,AX
  1311.     MOV DX,CS:SB_IO_ADDR
  1312.     ADD DX,04H
  1313.     MOV AX,04H              ;Voice Volume Register
  1314.     OUT DX,AL
  1315.     INC DX
  1316.     MOV AX,BX               ;Get volume and set
  1317.     OUT DX,AL
  1318. EXIT_VOL:
  1319.     RET
  1320.  
  1321. SET_VOLUME ENDP
  1322.  
  1323. SET_MODE PROC NEAR
  1324.  
  1325.     MOV AX,CS:STEREO        ;Get mono or stereo mode
  1326.     CMP AX,CS:PRE_MODE      ;Same mode as before?
  1327.     JE SM_EXIT
  1328.     CMP CS:SB_VER,0300H     ;Sound Blaster Pro
  1329.     JL SM_EXIT
  1330.     CMP CS:SB_VER,0400H     ;only
  1331.     JGE SM_EXIT
  1332.     MOV DX,CS:SB_IO_ADDR
  1333.     ADD DX,4
  1334.     MOV CS:PRE_MODE,AX      ;Save current mode
  1335.     CMP AX,2                ;Stereo or mono
  1336.     JE SET_STEREO
  1337.     MOV AL,00CH             ;Restore filter status
  1338.     OUT DX,AL
  1339.     INC DX
  1340.     MOV AX,CS:OUT_FILTER
  1341.     OUT DX,AL
  1342.     DEC DX
  1343.     MOV AL,00EH             ;Set hardware to mono mode
  1344.     OUT DX,AL
  1345.     INC DX
  1346.     IN AL,DX
  1347.     AND AL,0FDH
  1348.     OUT DX,AL
  1349.     JMP SM_EXIT
  1350. SET_STEREO:
  1351.     MOV AX,00EH             ;Set hardware to stereo mode
  1352.     OUT DX,AL
  1353.     INC DX
  1354.     IN AL,DX
  1355.     OR AL,002H
  1356.     OUT DX,AL
  1357.     DEC DX
  1358.     MOV AX,00EH
  1359.     OUT DX,AL
  1360.     INC DX
  1361.     IN AL,DX
  1362.     MOV CS:OUT_FILTER,AX
  1363.     OR AL,020H
  1364.     OUT DX,AL
  1365. SM_EXIT:
  1366.     RET
  1367.  
  1368. SET_MODE ENDP
  1369.  
  1370. _TEXT   ENDS
  1371.     END
  1372.  
  1373.